package top.guxx.mall.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.google.common.eventbus.EventBus;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import top.guxx.mall.MallException;
import top.guxx.mall.config.RedisService;
import top.guxx.mall.constants.Constants;
import top.guxx.mall.dao.IOrderDao;
import top.guxx.mall.dao.IProductDao;
import top.guxx.mall.domain.dto.OrderItem;
import top.guxx.mall.domain.dto.PaidOrderDTO;
import top.guxx.mall.domain.po.PayOrder;
import top.guxx.mall.domain.po.Product;
import top.guxx.mall.domain.req.ShopCartReq;
import top.guxx.mall.domain.res.PayOrderRes;
import top.guxx.mall.domain.vo.ProductVO;
import top.guxx.mall.rpc.ProductRPC;
import top.guxx.mall.service.IOrderService;
import top.guxx.mall.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Author：Guxx
 * @Description：
 * @Date：2025/2/19 0:18
 * @Filename：OrderService
 */
@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {
    @Value("${alipay.notify_url}")
    private String notifyUrl;
    @Value("${alipay.return_url}")
    private String returnUrl;
    @Resource
    private IOrderDao orderDao;
    @Resource
    private ProductRPC productRPC;

    @Resource
    private IProductDao productDao;

    @Resource
    private AlipayClient alipayClient;
    @Resource
    private EventBus eventBus;

    @Resource
    private RedisService redisService;

    @Override
    public PayOrderRes createOrder(ShopCartReq shopCartReq) throws Exception {
        PayOrder queryOrder = new PayOrder();
        Set<String> set = shopCartReq.getProductCountMap().keySet();
        String ids = StringUtils.list2StringByDelimiter(new ArrayList<>(set), Constants.SPLIT);
        queryOrder.setUserId(shopCartReq.getUserId());
        queryOrder.setProductIds(ids);
        PayOrder unpaidOrder = orderDao.queryUnPayOrder(queryOrder);

        //1. 查询订单是否创建
        if (null != unpaidOrder && Constants.OrderStatusEnum.PAY_WAIT.getCode().equals(unpaidOrder.getStatus())) {
            log.info("创建订单-存在，已存在未支付订单。userId:{} productId:{} orderId:{}", shopCartReq.getUserId(), set, unpaidOrder.getOrderId());
            return PayOrderRes.builder()
                    .orderId(unpaidOrder.getOrderId())
                    .payUrl(unpaidOrder.getPayUrl())
                    .build();
        } else if (null != unpaidOrder && Constants.OrderStatusEnum.CREATE.getCode().equals(unpaidOrder.getStatus())) {
            //订单已创建
            return PayOrderRes.builder()
                    .orderId(unpaidOrder.getOrderId())
                    .payUrl(unpaidOrder.getPayUrl())
                    .build();
        }

        //2. 查询商品，创建订单
        Map<String, String> map = shopCartReq.getProductCountMap();

        for (String key : map.keySet()) {
            Long count = Long.parseLong(map.get(key).toString());
            long surplus = redisService.decr(Constants.RedisKey.STOCK.getCode() + key,count);
            if (surplus < 0){
                throw MallException.builder()
                        .errorCode(Constants.ResponseCode.UN_ERROR.getCode())
                        .errMsg("库存不足扣减失败！")
                        .build();
            }
        }

        List<ProductVO> productVO = productRPC.queryProductByProductId(new ArrayList<>(set));
        BigDecimal amount = new BigDecimal(0);
        ArrayList<String> nameList = new ArrayList<>();
        List<OrderItem> info = new ArrayList<>();
        for (ProductVO vo : productVO) {
            nameList.add(vo.getProductName());
            String count = map.get(vo.getProductId()).toString();
            BigDecimal countBD = new BigDecimal(count);
            BigDecimal singleProductTotalPrice = vo.getPrice().multiply(countBD);
            amount = amount.add(singleProductTotalPrice);
            info.add(OrderItem.builder()
                    .productName(vo.getProductName())
                    .productId(vo.getProductId())
                    .picUrl(vo.getUrl())
                    .price(vo.getPrice())
                    .nums(Integer.parseInt(shopCartReq.getProductCountMap().get(vo.getProductId())))
                    .build());
        }


        String names = StringUtils.list2StringByDelimiter(nameList, Constants.SPLIT);
        String orderId = RandomStringUtils.randomNumeric(16);
        orderDao.insert(PayOrder.builder()
                .userId(shopCartReq.getUserId())
                .productIds(ids)
                .productNames(names)
                .productInfo(JSONObject.toJSONString(info))
                .orderId(orderId)
                .totalAmount(amount)
                .orderTime(new Date())
                .status(Constants.OrderStatusEnum.CREATE.getCode())
                .build());

        // 3. 创建支付单
        PayOrder payOrder = doPrePayOrder(orderId,ids,names,amount);

        //将订单商品数量上传到Redis
        redisService.putAllWithExpire(orderId,map, 60 * 15);

        return PayOrderRes.builder()
                .orderId(orderId)
                .payUrl(payOrder.getPayUrl())
                .build();
    }

    @Override
    public void changeOrderPaySuccess(String orderId) {
        PayOrder payOrderReq = new PayOrder();
        payOrderReq.setOrderId(orderId);
        payOrderReq.setStatus(Constants.OrderStatusEnum.PAY_SUCCESS.getCode());
        orderDao.changeOrderPaySuccess(payOrderReq);

        eventBus.post(JSON.toJSONString(payOrderReq));

    }

    @Override
    public List<String> queryTimeoutCloseOrderList() {
        return orderDao.queryTimeOutOrders();
    }

    @Override
    public boolean changeOrderClose(String orderId) {
        return orderDao.closeOrder(orderId);
    }

    @Override
    public List<String> queryNoPayNotifyOrder() {
        return orderDao.queryNoPayNotifyOrder();
    }

    @Override
    public List<PaidOrderDTO> queryPaidOrder(String userId) {
        List<PayOrder> orders = orderDao.queryPaidOrder(userId);
        List<PaidOrderDTO> res = new ArrayList<>();
        for (PayOrder order : orders) {
            List<OrderItem> list = JSON.parseArray(order.getProductInfo(), OrderItem.class);
            res.add(PaidOrderDTO.builder()
                    .gmtCreateTime(order.getCreateTime())
                            .orderId(order.getOrderId())
                            .totalAmount(order.getTotalAmount())
                            .orderItems(list)
                    .build());
        }
        return res;
    }

    private PayOrder doPrePayOrder(String orderId,String productId, String productName, BigDecimal totalAmount) throws AlipayApiException {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(notifyUrl);
        request.setReturnUrl(returnUrl);
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderId);
        bizContent.put("total_amount", totalAmount.toString());
        bizContent.put("subject", productName);
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        String form = alipayClient.pageExecute(request).getBody();
        PayOrder payOrder = new PayOrder();
        payOrder.setPayUrl(form);
        payOrder.setStatus(Constants.OrderStatusEnum.PAY_WAIT.getCode());
        payOrder.setOrderId(orderId);

        orderDao.updateOrderPayInfo(payOrder);

        return payOrder;
    }

}
